package com.toolkit.util;

import com.alibaba.fastjson2.JSON;
import java.nio.charset.Charset;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.NameValuePair;

import java.security.cert.CertificateException;
import java.util.Map.Entry;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.net.ssl.*;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;

import java.nio.charset.StandardCharsets;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

@Component
@Slf4j
public class HttpAPIUtil {
    @Autowired
    private CloseableHttpClient httpClient;

    @Autowired
    private RequestConfig config;

    /**
     * 不带参数的get请求，如果状态码为200，则返回body，如果不为200，则返回null
     *
     * @param url
     * @return
     * @throws Exception
     */
    public String doGet(String url) throws Exception {
        // 声明 http get 请求
        HttpGet httpGet = new HttpGet(url);

        // 装载配置信息
        httpGet.setConfig(config);

        // 发起请求
        CloseableHttpResponse response = this.httpClient.execute(httpGet);

        // 判断状态码是否为200
        if (response.getStatusLine().getStatusCode() == 200) {
            // 返回响应体的内容
            return EntityUtils.toString(response.getEntity(), "UTF-8");
        }
        return null;
    }
    public static Map<String, Object> doMapPut(String putUrl, Object paramsMap, Map<String, String> headersMap) throws Exception{
        HttpPut put = new HttpPut(putUrl);
        StringEntity entity = new StringEntity(JSON.toJSONString(paramsMap), ContentType.APPLICATION_JSON);
        if(headersMap != null) {
            Set<Entry<String, String>> entrySet = headersMap.entrySet();
            for(Entry<String, String> entry : entrySet) {
                put.addHeader(new BasicHeader(entry.getKey(), entry.getValue()));
            }
        }
        put.setHeader("Content-Type", "application/json");
        put.setEntity(entity);
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000).build();
        put.setConfig(requestConfig);
        SSLContext sslContext = getSSLContext();
        Registry<ConnectionSocketFactory> socketFactoryRegistry =
                RegistryBuilder.<ConnectionSocketFactory>create()
                        .register("http", PlainConnectionSocketFactory.INSTANCE)
                        .register("https", new SSLConnectionSocketFactory(sslContext)).build();
        PoolingHttpClientConnectionManager mananger = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
        mananger.setMaxTotal(100);
        mananger.setDefaultMaxPerRoute(20);
        CloseableHttpClient client = HttpClients
                .custom()
                .setDefaultRequestConfig(requestConfig)
                .setConnectionManager(mananger)
                .build();
        org.apache.http.HttpResponse response = client.execute(put);
        if(response.getStatusLine().getStatusCode() == 200) {
            String result = EntityUtils.toString(response.getEntity());
            @SuppressWarnings("unchecked")
            Map<String, Object> resultMap = (Map<String, Object>) JSON.parse(result);
            return resultMap;
        } else {
            throw new RuntimeException("httpclient response state is " + response.getStatusLine().getStatusCode() + " response body is " + EntityUtils.toString(response.getEntity()));
        }
    }
    /**
     * 带参数的get请求，如果状态码为200，则返回body，如果不为200，则返回null
     *
     * @param url
     * @return
     * @throws Exception
     */
    public static String doGet(String url, Map<String, Object> map) throws Exception {
        String result = "";
        CloseableHttpClient httpClient = HttpClients.createDefault();
        CloseableHttpResponse response = null;
        HttpEntity entity = null;
        if (map != null) {
            Set<String> set = map.keySet();
            StringBuffer sBuffer = new StringBuffer();
            sBuffer.append(url + "?");
            for (String key : set) {
                sBuffer.append(key + "=" + map.get(key) + "&");
            }
            url = sBuffer.toString();
            url = url.substring(0, url.length() - 1);

        }
        HttpGet method = new HttpGet(url);
        response = httpClient.execute(method);
        if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) {
            entity = response.getEntity();
            result = EntityUtils.toString(entity);
        }

        return result;
    }

    public static Map<String, Object> doMapPost(String postUrl, Object paramsMap, Map<String, String> headersMap) throws Exception{
        return doMapPost(postUrl, paramsMap, headersMap, Charset.forName("utf-8"));
    }
    public static Map<String, Object> doMapPost(String postUrl, Object paramsMap, Map<String, String> headersMap, Charset charset) throws Exception {
        CloseableHttpResponse response = null;
        CloseableHttpClient client = null;
        try {
            HttpPost post = new HttpPost(postUrl);
            StringEntity entity = new StringEntity(JSON.toJSONString(paramsMap), ContentType.APPLICATION_JSON);
            if(headersMap != null) {
                Set<Entry<String, String>> entrySet = headersMap.entrySet();
                for(Entry<String, String> entry : entrySet) {
                    post.addHeader(new BasicHeader(entry.getKey(), entry.getValue()));
                }
            }
            post.setHeader("Content-Type", "application/json");
            post.setEntity(entity);
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000).build();
            post.setConfig(requestConfig);
            SSLContext sslContext = getSSLContext();
            Registry<ConnectionSocketFactory> socketFactoryRegistry =
                    RegistryBuilder.<ConnectionSocketFactory>create()
                            .register("http", PlainConnectionSocketFactory.INSTANCE)
                            .register("https", new SSLConnectionSocketFactory(sslContext)).build();
            PoolingHttpClientConnectionManager mananger = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            mananger.setMaxTotal(100);
            mananger.setDefaultMaxPerRoute(20);
            client = HttpClients
                    .custom()
                    .setDefaultRequestConfig(requestConfig)
                    .setConnectionManager(mananger)
                    .build();
            response = client.execute(post);
            if(response.getStatusLine().getStatusCode() == 200) {
                String result = EntityUtils.toString(response.getEntity(), charset);
//                log.info("调用航信接口信息为:{}",result);
                @SuppressWarnings("unchecked")
                Map<String, Object> resultMap = (Map<String, Object>) JSON.parse(result);
                return resultMap;
            } else {
                throw new RuntimeException("httpclient response state is " + response.getStatusLine().getStatusCode() + " response body is " + EntityUtils.toString(response.getEntity()));
            }
        } finally {
            if(response != null) {
                response.close();
            }
            if(client != null) {
                client.close();
            }
        }
    }

    public static Map<String, Object> doMapDelete(String deleteUrl, Object paramsMap, Map<String, String> headersMap) throws Exception{
        CloseableHttpClient client = null;
        CloseableHttpResponse response = null;
        try {
            HttpEntityEnclosingRequestBase delete = new HttpEntityEnclosingRequestBase() {
                @Override
                public String getMethod() {
                    return "DELETE";
                }
            };
            delete.setURI(URI.create(deleteUrl));
            StringEntity entity = new StringEntity(JSON.toJSONString(paramsMap), ContentType.APPLICATION_JSON);
            if(headersMap != null) {
                Set<Entry<String, String>> entrySet = headersMap.entrySet();
                for(Entry<String, String> entry : entrySet) {
                    delete.addHeader(new BasicHeader(entry.getKey(), entry.getValue()));
                }
            }
            delete.setHeader("Content-Type", "application/json");
            delete.setEntity(entity);
            RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(10000).setConnectTimeout(10000).build();
            delete.setConfig(requestConfig);
            SSLContext sslContext = getSSLContext();
            Registry<ConnectionSocketFactory> socketFactoryRegistry =
                    RegistryBuilder.<ConnectionSocketFactory>create()
                            .register("http", PlainConnectionSocketFactory.INSTANCE)
                            .register("https", new SSLConnectionSocketFactory(sslContext)).build();
            PoolingHttpClientConnectionManager mananger = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            mananger.setMaxTotal(100);
            mananger.setDefaultMaxPerRoute(20);
            client = HttpClients
                    .custom()
                    .setDefaultRequestConfig(requestConfig)
                    .setConnectionManager(mananger)
                    .build();
            response = client.execute(delete);
            if(response.getStatusLine().getStatusCode() == 200) {
                String result = EntityUtils.toString(response.getEntity());
                @SuppressWarnings("unchecked")
                Map<String, Object> resultMap = (Map<String, Object>) JSON.parse(result);
                return resultMap;
            } else {
                throw new RuntimeException("httpclient response state is " + response.getStatusLine().getStatusCode() + " response body is " + EntityUtils.toString(response.getEntity()));
            }
        } finally {
            if(response != null) {
                response.close();
            }
            if(client != null) {
                client.close();
            }
        }
    }
    private static SSLContext getSSLContext() {
        try {
            // 这里可以填两种值 TLS和LLS , 具体差别可以自行搜索
            SSLContext sc = SSLContext.getInstance("TLS");
            // 构建新对象
            X509TrustManager manager = new X509TrustManager() {

                @Override
                public void checkClientTrusted(X509Certificate[] chain, String authType)
                        throws java.security.cert.CertificateException {
                }

                @Override
                public void checkServerTrusted(X509Certificate[] chain, String authType)
                        throws java.security.cert.CertificateException {
                }

                @Override
                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }

            };
            sc.init(null, new TrustManager[]{manager}, null);
            return sc;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 带参数的post请求
     *
     * @param url
     * @param map
     * @return
     * @throws Exception
     */
    public static String doPost(String url, Map<String, Object> map) throws Exception {
        // 声明httpPost请求
        CloseableHttpClient httpClient = HttpClients.createDefault();
        HttpPost httpPost = new HttpPost(url);
        CloseableHttpResponse response = null;
        String resultString = "";
        // 判断map是否为空，不为空则进行遍历，封装from表单对象
        if (map != null) {
            List<NameValuePair> list = new ArrayList<NameValuePair>();
            for (Map.Entry<String, Object> entry : map.entrySet()) {
                list.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
            }
            // 构造from表单对象
            UrlEncodedFormEntity urlEncodedFormEntity = new UrlEncodedFormEntity(list, "UTF-8");
            // 把表单放到post里
            httpPost.setEntity(urlEncodedFormEntity);
        }
        //执行post请求
        response = httpClient.execute(httpPost);
        if (response != null && response.getStatusLine().getStatusCode() == 200) {
            resultString = EntityUtils.toString(response.getEntity(), "UTF-8");
        }
        return resultString;
    }

    /**
     * 远程调接口传json格式数据
     * @param url
     * @param map
     * @return
     * @throws Exception
     */
    public static String doPostJson(String url, Map<String, Object> map) throws Exception {
        log.info("url:{}",url,map);
        String resultString="";
        ObjectMapper objectMapper = new ObjectMapper();
        String  jsonBody=objectMapper.writeValueAsString(map);
        // 创建HttpClient实例
        HttpClient httpClient = HttpClient.newHttpClient();
        // 构建HTTP请求
        HttpRequest request = HttpRequest.newBuilder()
                .uri(URI.create(url))
                .header("Content-Type", "application/json")
                .POST(HttpRequest.BodyPublishers.ofString(jsonBody, StandardCharsets.UTF_8))
                .build();
        try {
            // 发送请求并获取响应
            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
            if (response != null) {
                resultString =response.body();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return resultString;
    }


    /**
     * Trust every server - dont check for any certificate
     */
    private static void trustAllHosts() {
        final String TAG = "trustAllHosts";
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[]{new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[]{};
            }

            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
            }
        }};
        // Install the all-trusting trust manager
        try {
            SSLContext sc = SSLContext.getInstance("TLS");
            sc.init(null, trustAllCerts, new java.security.SecureRandom());
            HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    final static HostnameVerifier DO_NOT_VERIFY = new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return true;
        }
    };

    /**
     * HttpPost请求
     * @param vUrl 请求地址
     * @param content 参数内容
     * @param headerMap 报文类型
     * @return
     */
    public static String doPostByJson(String vUrl, String content,Map<String,String> headerMap) {
        try {
            URL url = new URL(vUrl);
            trustAllHosts();
            HttpURLConnection httpconn = null;
            if (url.getProtocol().toLowerCase().equals("https")) {
                HttpsURLConnection https = (HttpsURLConnection) url.openConnection();
                https.setHostnameVerifier(DO_NOT_VERIFY);
                httpconn = https;
            } else {
                httpconn = (HttpURLConnection) url.openConnection();
            }
            httpconn.setRequestProperty("encoding", "UTF-8");// 添加请求属性
            if(headerMap != null && headerMap.size()>0) {
                for(String key:headerMap.keySet()){
                    String value = headerMap.get(key).toString();
                    httpconn.setRequestProperty(key, value);
                }
            }
            httpconn.setDoInput(true);// 允许输入
            httpconn.setDoOutput(true);// 允许输出
            httpconn.setRequestMethod("POST");// POST请求 要在获取输入输出流之前设置 否则报错
            // 输出
            OutputStream os = httpconn.getOutputStream();
            OutputStreamWriter osw = new OutputStreamWriter(os, "UTF-8");
            BufferedWriter bw = new BufferedWriter(osw);
            bw.write(content);
            bw.flush();

            // 输入
            InputStream in = httpconn.getInputStream();
            InputStreamReader isr = new InputStreamReader(in, "UTF-8");
            BufferedReader br = new BufferedReader(isr);

            String line;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }
            bw.close();
            osw.close();
            os.close();
            br.close();
            isr.close();
            in.close();
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 不带参数post请求
     *
     * @param url
     * @return
     * @throws Exception
     */
    public String doPost(String url) throws Exception {
        return this.doPost(url, null);
    }
}
